package com.jevons.muffin.net.loader;


import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.jevons.muffin.net.bean.DownloadResponse;
import com.jevons.muffin.net.bean.NullObject;
import com.jevons.muffin.net.exception.ResponseException;
import com.jevons.muffin.net.inter.IResponse;
import com.jevons.muffin.net.observable.DownloadObservable;
import com.jevons.muffin.net.typetoken.ResTypeToken;

import io.reactivex.Observable;
import io.reactivex.ObservableSource;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.annotations.NonNull;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;

/**
 * 网络请求操作基类
 * @author linaisheng
 * Created at 2019/3/14.
 */

public class BaseLoader {

    private static final String TAG = BaseLoader.class.getSimpleName();

    /**
     * 请求结果直接解析成T泛型
     * @param observable Retrofit请求任务
     * @param <T>   json解析结果
     * @return
     */
    protected final  <T>Observable<T> observe(Observable<T> observable) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }


    /**
     * 请求结果带业务判断码，解析成真的的结果T泛型
     * @param observable Retrofit请求任务
     * @param <T>   json解析结果
     * @return
     */
    protected final <T>Observable<T> observeWithParse(
            Observable<? extends IResponse<T>> observable) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map(new Function<IResponse<T>, T>() {
                    @Override
                    public T apply(@NonNull IResponse<T> tiResponse) throws Exception {
                        return doParse(tiResponse);
                    }
                });
    }

    /**
     * 请求结果带业务判断码，解析成真的的结果T泛型
     * 回调不在主线程中
     * @param observable Retrofit请求任务
     * @param <T>   json解析结果
     * @return
     */
    protected final  <T>Observable<T> observeWithParseOnIo(
            Observable<? extends IResponse<T>> observable) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(new Function<IResponse<T>, T>() {
                    @Override
                    public T apply(@NonNull IResponse<T> tiResponse) throws Exception {
                        return doParse(tiResponse);
                    }
                });
    }




    /**
     * Retrofit文件下载，不带断点保存
     * @param saveFilePath
     * @param observable
     * @return
     */
    protected final Observable<DownloadResponse> downloadFile(
            final String saveFilePath,
            Observable<ResponseBody> observable) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .flatMap(new Function<ResponseBody, ObservableSource<DownloadResponse>>() {
                    @Override
                    public ObservableSource<DownloadResponse> apply(@NonNull final ResponseBody responseBody) throws Exception {
                        return Observable.create(new DownloadObservable(saveFilePath, responseBody));
                    }
                }).observeOn(AndroidSchedulers.mainThread());
    }


    /**
     * 文件上传，直接解析成T泛型
     * @param observable
     * @param t
     * @param <T>
     * @return
     */
    protected final <T>Observable<T> uploadFile(
            Observable<ResponseBody> observable,
            final Class<T> t) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(new Function<ResponseBody, T>() {
                    @Override
                    public T apply(@NonNull ResponseBody responseBody) throws Exception {
                        TypeToken typeToken = TypeToken.get(t);
                        Gson gson = new Gson();
                        JsonReader jsonReader = gson.newJsonReader(responseBody.charStream());
                        TypeAdapter<T> adapter = gson.getAdapter(typeToken);
                        return adapter.read(jsonReader);
                    }
                }).observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 文件上传，根据业务码判断解析成T泛型
     * @param observable
     * @param typeToken
     * @param <T>
     * @return
     */
    protected final <T>Observable<T> uploadFileWithParse(
            Observable<ResponseBody> observable,
            final ResTypeToken<? extends IResponse<T>> typeToken) {
        return observable.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(new Function<ResponseBody, T>() {
                    @Override
                    public T apply(@NonNull ResponseBody responseBody) throws Exception {
                        Gson gson = new Gson();
                        JsonReader jsonReader = gson.newJsonReader(responseBody.charStream());
                        IResponse<T> tiResponse = gson.getAdapter(typeToken).read(jsonReader);
                        //判断业务是否成功
                        if (tiResponse.isSuccess()) {
                            return tiResponse.getResult();
                        } else {
                            throw  new ResponseException(tiResponse.getErrorCode(),
                                    tiResponse.getReason(), null);
                        }
                    }
                }).observeOn(AndroidSchedulers.mainThread());
    }


    public final Observable<Long> getDownloadSize(
            Observable<ResponseBody> observable) {
        return observable
                .subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(Schedulers.io())
                .map(new Function<ResponseBody, Long>() {
                    @Override
                    public Long apply(ResponseBody responseBody) throws Exception {
                        long lenth = responseBody.contentLength();
                        return lenth;
                    }
                })
                .observeOn(AndroidSchedulers.mainThread());
    }


    protected final  <T> T doParse(@NonNull IResponse<T> tiResponse) throws Exception {
        if (tiResponse.isSuccess()) {
            if (tiResponse.getResult() == null) {
                return (T) new NullObject();
            }
            return tiResponse.getResult();
        } else {
            throw  new ResponseException(tiResponse.getErrorCode(),
                    tiResponse.getReason(), null);
        }
    }




}
